package com.cx.bank.manager;

import com.cx.bank.dao.AccountRepository;
import com.cx.bank.dao.TransferRepository;
import com.cx.bank.domain.Account;
import com.cx.bank.domain.Transfer;
import com.cx.bank.exception.AccountException;
import com.cx.bank.exception.AccountOverDrawnException;
import com.cx.bank.exception.InvalidDepositException;
import com.cx.bank.exception.ServiceException;
import com.cx.bank.util.MD5Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * AccountManagerImpl
 *
 * @author LongShu 2017/06/15
 */
@Service
@Transactional// 开启事务
public class AccountManagerImpl implements AccountManager {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private TransferRepository transferRepository;

    @Override
    public Account login(String card, String password) throws ServiceException {
        Account acc = queryAccount(card);
        // 加密密码后比较
        password = MD5Util.md5(password);
        if (Objects.equals(acc.getPassword(), password)) {
            return acc;
        } else {
            throw new AccountException("账号或密码错误!");
        }
    }

    @Override
    public Account register(Account account) throws ServiceException {
        try {
            Account acc = accountRepository.findByCard(account.getCard());
            if (acc != null) {
                throw new AccountException(account.getCard() + "账号已存在!");
            }
            // 加密密码后存入数据库
            String md5 = MD5Util.md5(account.getPassword());
            account.setPassword(md5);
            account.setId(null);
            account.setMoney(0.0);
            account.setCreateTime(new Date());

            account = accountRepository.saveAndFlush(account);
            return account;
        } catch (DataAccessException e) {
            logger.warn(e.getMessage(), e);
            throw new ServiceException("注册账户失败!");
        }
    }

    @Override
    @Transactional(readOnly = true)
    public Account queryAccount(String card) throws ServiceException {
        try {
            Account acc = accountRepository.findByCard(card);
            if (acc == null) {
                throw new AccountException(card + "账户不存在!");
            }
            return acc;
        } catch (DataAccessException e) {
            logger.warn(e.getMessage(), e);
            throw new ServiceException("查询账户失败!");
        }
    }

    @Override
    public double deposit(String card, double money) throws ServiceException {
        if (money <= 0) {
            throw new InvalidDepositException("存款金额不能小于0!");
        }
        Account acc = queryAccount(card);

        acc.setMoney(acc.getMoney().add(BigDecimal.valueOf(money)));
        update(acc);

        return getMoney(acc.getMoney());
    }

    @Override
    public double withdrawals(String card, double money) throws ServiceException {
        Account acc = queryAccount(card);
        if (money > getMoney(acc.getMoney())) {
            throw new AccountOverDrawnException(card + "账户金额不足!");
        }
        acc.setMoney(acc.getMoney().subtract(BigDecimal.valueOf(money)));
        update(acc);

        return getMoney(acc.getMoney());
    }

    @Override
    public Transfer transfer(Transfer transfer) throws ServiceException {
        double money = transfer.getMoney().doubleValue();
        if (money <= 0) {
            throw new AccountException("转账金额不能小于0!");
        }
        transfer.setCreateTime(new Date());

        withdrawals(transfer.getFromCard(), money);
        deposit(transfer.getToCard(), money);

        transfer = transferRepository.saveAndFlush(transfer);
        return transfer;
    }


    @Override
    @Transactional(readOnly = true)
    public List<Transfer> transferRecord(String card) {
        List<Transfer> transferList = transferRepository.findByFromCard(card);
        return transferList;
    }

    /**
     * 更新账户
     */
    private void update(Account account) {
        try {
            accountRepository.save(account);
        } catch (DataAccessException e) {
            logger.error(e.getMessage(), e);
            throw new AccountException("更新账户失败!");
        }
    }

    /**
     * BigDecimal -> double
     */
    private double getMoney(BigDecimal money) {
        if (money == null) {
            return 0;
        }
        return money.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

}
